package service

import (
	"context"
	"fmt"
	"time"

	"github.com/google/uuid"

	"bilinadmin/pkg/util"

	"bilinadmin/internal/object"

	"github.com/pkg/errors"

	pb "bilinadmin/api/pb/server"
	"bilinadmin/internal/dao"
	"bilinadmin/internal/model"
	"bilinadmin/pkg/lueerror"
)

type empSrv struct {
	*Service
	name string
}

var eSrv *empSrv

// InitEmployeeService 初始化员工逻辑层
func InitEmployeeService() {
	bSrv = &bsService{
		Service: service,
		name:    "employee_service",
	}
}

// GetEmployeeService 获取员工辑层
func GetEmployeeService() *empSrv {
	return eSrv
}

// CreateEmployee 创建员工
func (srv *empSrv) CreateEmployee(ctx context.Context, brandId int64, name, mobile, email, accountId string) (*pb.EmployeeResponse, lueerror.LueError) {
	// 检查品牌是否有效
	brand, err := dao.GetBrandDao().GetBrandById(ctx, brandId)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	if brand == nil || !brand.IsValid() {
		return nil, lueerror.InvalidBrand(errors.New("无效的品牌"))
	}
	// 检查员工是否已经注册
	emp, err := dao.GetEmployeeDao().GetEmpByBrandAndAccount(ctx, brandId, accountId)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	// 如果没有则创建员工
	if emp == nil {
		emp = model.NewEmployee(brandId, name, mobile, email, accountId, model.EmployeeStatusOK, util.GetZeroTime())
		emp.Id, err = dao.GetEmployeeDao().CreateEmployee(ctx, emp)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
	}
	return &pb.EmployeeResponse{
		EmpId:   emp.Id,
		BrandId: emp.BrandId,
		Name:    emp.Name,
		Mobile:  emp.Mobile,
		Email:   emp.Email,
	}, nil
}

func (srv *empSrv) getEmpRole(ctx context.Context, roleId, brandId, storeId int64) (*model.EmpRole, lueerror.LueError) {
	refId, refType := model.GetRefInfoForBrandStore(brandId, storeId)
	role, err := dao.GetRoleDao().GetEmpRoleByIdAndRef(ctx, roleId, refId, refType)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	if role == nil {
		return nil, lueerror.InvalidRole(errors.New("角色不存在"))
	}
	return role, nil
}

// 统一账号端生成邀请
func (srv *empSrv) accountInvitation(ctx context.Context, mobile, email, userName string) (*object.AccountInfo, lueerror.LueError) {
	ret, err := dao.GetBilinVendorDao().EmpAccountInvitation(ctx, mobile, email, userName)
	if err != nil {
		return nil, lueerror.GrpcErr(err)
	}
	return ret, nil
}

func (srv *empSrv) createEmp(ctx context.Context, brandId int64, name, mobile, email, accId, status string, entryDate time.Time) (*model.Employee, lueerror.LueError) {
	var err error
	innerSt := model.GetInnerEmpStatus(status)
	emp := model.NewEmployee(brandId, name, mobile, email, accId, innerSt, entryDate)
	emp.Id, err = dao.GetEmployeeDao().CreateEmployee(ctx, emp)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	return emp, nil
}

func (srv *empSrv) createOrUpdateOperator(ctx context.Context, brandId, storeId, empId, roleId, invitor int64, status int8) (*model.Operator, lueerror.LueError) {
	// 检查运营角色是否存在
	refId, refType := model.GetRefInfoForBrandStore(brandId, storeId)
	op, err := dao.GetOperatorDao().GetOperator(ctx, empId, refId, refType)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	if op != nil {
		if status == model.OpStatusInviting {
			return nil, lueerror.OpIsExist(fmt.Errorf("员工 %d 已经存在运营角色", empId))
		}
		op.Update(roleId, invitor)
		err = dao.GetOperatorDao().UpdateOperatorById(ctx, op)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		return op, nil
	}
	// 创建新角色
	// 检查门店是否存在
	if storeId != 0 {
		store, err := dao.GetStoreDao().GetStoreById(ctx, storeId)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		if store == nil || store.BrandId != brandId {
			return nil, lueerror.InvalidStore(fmt.Errorf("品牌:%d, 门店：%d 不存在", brandId, storeId))
		}
		if store.SupEmpId == empId {
			return nil, lueerror.OpIsExist(fmt.Errorf("员工 %d 已经是超级管理员", empId))
		}
	} else {
		brand, err := dao.GetBrandDao().GetBrandById(ctx, brandId)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		if brand.SuEmpId == empId {
			return nil, lueerror.OpIsExist(fmt.Errorf("员工 %d 已经是超级管理员", empId))
		}
	}

	op = model.NewOperator(brandId, refId, empId, roleId, invitor, refType, status)
	op.Id, err = dao.GetOperatorDao().CreateOperator(ctx, op)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	return op, nil
}

// 加载品牌或门店下所有仓库
func (srv *empSrv) getAllInventories(ctx context.Context, brandId, storeId int64) (map[int64]*model.Inventory, []int64, lueerror.LueError) {
	invs, err := dao.GetInventoryDao().GetInventoriesByBrandStore(ctx, brandId, storeId)
	if err != nil {
		return nil, nil, lueerror.DbErr(err)
	}
	invMap := make(map[int64]*model.Inventory, len(invs))
	invIds := make([]int64, len(invs))
	for idx, inv := range invs {
		invIds[idx] = inv.Id
		invMap[inv.Id] = inv
	}
	return invMap, invIds, nil
}

// 创建仓库运营
// 仓库运营暂时没有角色信息
func (srv *empSrv) createOrUpdateInventoryOperator(ctx context.Context, brandId, storeId, empId int64, invIds []int64, status int8, modifier int64) lueerror.LueError {
	// 检查仓库
	allInvMap, allInvIds, errL := srv.getAllInventories(ctx, brandId, storeId)
	if errL != nil {
		return errL
	}
	for _, invId := range invIds {
		_, found := allInvMap[invId]
		if !found {
			return lueerror.InvalidInventory(fmt.Errorf("品牌：%d, 门店： %d, 仓库 %d 不存在", brandId, storeId, invId))
		}
	}
	// 获取已有运营仓库角色
	invOps, err := dao.GetOperatorDao().LockOperatorsByRefIds(ctx, brandId, empId, model.RefTypeInventory, allInvIds)
	if err != nil {
		return lueerror.DbErr(err)
	}
	existOps := make(map[int64]*model.Operator, len(invOps))
	for _, op := range invOps {
		existOps[op.RefId] = op
	}
	// 分离出需要新增或删除的仓库运营
	// 删除的
	var delOps []*model.Operator
	// 新建的
	var newOps []*model.Operator
	// 更新的，暂时不需要
	for _, invId := range invIds {
		_, found := existOps[invId]
		if found {
			// 在 existOps 里删除已有，剩下的就是需要删除的
			delete(existOps, invId)
		} else {
			// 不存在则是需要新增的
			newOps = append(newOps, model.NewOperator(brandId, invId, empId, 0, modifier, model.RefTypeInventory, status))
		}
	}
	// 需要删除的
	for _, opId := range existOps {
		delOps = append(delOps, opId)
	}
	// 新建仓库运营
	err = dao.GetOperatorDao().CreateOperators(ctx, newOps)
	if err != nil {
		return lueerror.DbErr(err)
	}
	// 删除仓库运营
	err = dao.GetOperatorDao().DelOperatorByIds(ctx, delOps, modifier)
	if err != nil {
		return lueerror.DbErr(err)
	}
	return nil
}

func (srv *empSrv) employeeInfoAgg(emp *model.Employee, role *model.EmpRole, op *model.Operator, invOps []*model.Operator) *object.EmployeeInfo {
	if emp == nil {
		return nil
	}
	ret := &object.EmployeeInfo{
		EmpId:     emp.Id,
		BrandId:   emp.BrandId,
		AccountId: emp.AccountId,
		Mobile:    emp.Mobile,
		Email:     emp.Email,
		Name:      emp.Name,
		EntryDate: emp.EntryDate,
	}
	if role != nil {
		ret.RoleId = role.Id
		ret.RoleName = role.Name
	}
	if op != nil {
		ret.Status = op.GetStatus()
	}
	invIds := make([]int64, len(invOps))
	for idx, inOp := range invOps {
		invIds[idx] = inOp.RefId
	}
	ret.InventoryIds = invIds
	return ret
}

// InviteEmployee 邀请员工
func (srv *empSrv) InviteEmployee(ctx context.Context, brandId int64, p *pb.EmployeeInvitationReq, invitor int64) (*pb.EmployeeInfoReply, lueerror.LueError) {
	if p == nil {
		return nil, nil
	}
	// 统一账号邀请生成
	acc, errL := srv.accountInvitation(ctx, p.Mobile, "", p.Name)
	if errL != nil {
		return nil, errL
	}
	// 检查员工是否已经注册
	emp, err := dao.GetEmployeeDao().GetEmpByBrandAndAccount(ctx, brandId, acc.GID)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}

	enDate, err := util.DateParse(p.EntryDate)

	ret, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		// 员工不存在，创建员工
		if emp == nil {
			if err != nil {
				return nil, lueerror.DbErr(err)
			}
			emp, errL = srv.createEmp(ctx, brandId, p.Name, p.Mobile, "", acc.GID, model.EmployeeStatusInvitingStr, enDate)
			if errL != nil {
				return nil, errL
			}
		}
		// 为员工添加运营角色
		var role *model.EmpRole
		if p.RoleId != 0 {
			// 角色检查
			role, errL = srv.getEmpRole(ctx, p.RoleId, brandId, p.StoreId)
			if errL != nil {
				return nil, errL
			}
		}
		op, errL := srv.createOrUpdateOperator(ctx, brandId, p.StoreId, emp.Id, p.RoleId, invitor, model.OpStatusInviting)
		if errL != nil {
			return nil, errL
		}
		// 新增仓库管理角色
		errL = srv.createOrUpdateInventoryOperator(ctx, brandId, p.StoreId, emp.Id, p.InventoryIds, model.OpStatusInviting, invitor)
		if errL != nil {
			return nil, errL
		}
		invOps, errL := srv.getInvOpInfoByEmpId(ctx, brandId, p.StoreId, emp.Id, false)
		if errL != nil {
			return nil, errL
		}
		ret := srv.employeeInfoAgg(emp, role, op, invOps)
		return ret, nil
	})
	if err != nil {
		return nil, parseLueerror(err)
	}
	res := ret.(*object.EmployeeInfo)
	return &pb.EmployeeInfoReply{
		EmpId:        res.EmpId,
		Name:         res.Name,
		Mobile:       res.Mobile,
		EntryDate:    util.TimeToDate(res.EntryDate),
		RoleId:       res.RoleId,
		RoleName:     res.RoleName,
		InventoryIds: res.InventoryIds,
		Status:       res.Status,
	}, nil
}

// 获取员工信息
func (srv *empSrv) getEmpInfoById(ctx context.Context, brandId, empId int64, isLock bool) (*model.Employee, lueerror.LueError) {
	var err error
	var emp *model.Employee
	if isLock {
		emp, err = dao.GetEmployeeDao().LockEmpById(ctx, brandId, empId)
	} else {
		emp, err = dao.GetEmployeeDao().GetEmpById(ctx, brandId, empId)
	}
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	return emp, nil
}

// 获取员工运营角色信息
func (srv *empSrv) getOpInfoByEmpId(ctx context.Context, empId, brandId, storeId int64, isLock bool) (*model.Operator, lueerror.LueError) {
	// 获取运营角色
	refId, refType := model.GetRefInfoForBrandStore(brandId, storeId)
	var err error
	var op *model.Operator
	if isLock {
		op, err = dao.GetOperatorDao().LockOperator(ctx, empId, refId, refType)
	} else {
		op, err = dao.GetOperatorDao().GetOperator(ctx, empId, refId, refType)
	}
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	return op, nil
}

// 获取仓库运营
func (srv *empSrv) getInvOpInfoByEmpId(ctx context.Context, brandId, storeId, empId int64, isLock bool) ([]*model.Operator, lueerror.LueError) {
	// 加载所有仓库
	_, invIds, errL := srv.getAllInventories(ctx, brandId, storeId)
	if errL != nil {
		return nil, errL
	}
	var err error
	var invOps []*model.Operator
	if isLock {
		invOps, err = dao.GetOperatorDao().LockOperatorsByRefIds(ctx, brandId, empId, model.RefTypeInventory, invIds)
	} else {
		invOps, err = dao.GetOperatorDao().GetOperatorsByRefIds(ctx, brandId, empId, model.RefTypeInventory, invIds)
	}
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	return invOps, nil
}

// GetEmployeeInfoBrief 简要员工信息
func (srv *empSrv) GetEmployeeInfoBrief(ctx context.Context, brandId, empId int64) (*pb.EmployeeInfoBriefReply, lueerror.LueError) {
	emp, errL := srv.getEmpInfoById(ctx, brandId, empId, false)
	if errL != nil {
		return nil, errL
	}
	if emp == nil {
		return nil, lueerror.InvalidEmployee(errors.New("员工不存在"))
	}
	return &pb.EmployeeInfoBriefReply{
		EmpId:   emp.Id,
		BrandId: emp.BrandId,
		Name:    emp.Name,
		Status:  emp.GetStatus(),
	}, nil
}

// GetEmployeeInfo 获取员工信息
func (srv *empSrv) GetEmployeeInfo(ctx context.Context, brandId, storeId, empId int64) (*pb.EmployeeInfoReply, lueerror.LueError) {
	emp, errL := srv.getEmpInfoById(ctx, brandId, empId, false)
	if errL != nil {
		return nil, errL
	}
	if emp == nil {
		return nil, lueerror.InvalidEmployee(errors.New("员工不存在"))
	}
	op, errL := srv.getOpInfoByEmpId(ctx, empId, brandId, storeId, false)
	if errL != nil {
		return nil, errL
	}
	// 仓库运营
	invOps, errL := srv.getInvOpInfoByEmpId(ctx, brandId, storeId, empId, false)
	if errL != nil {
		return nil, errL
	}
	var res *object.EmployeeInfo
	if op == nil {
		res = srv.employeeInfoAgg(emp, nil, nil, nil)
	} else {
		role, err := dao.GetRoleDao().GetEmpRoleById(ctx, op.RoleId)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		res = srv.employeeInfoAgg(emp, role, op, invOps)
	}
	return &pb.EmployeeInfoReply{
		EmpId:        res.EmpId,
		Name:         res.Name,
		Mobile:       res.Mobile,
		EntryDate:    util.TimeToDate(res.EntryDate),
		RoleId:       res.RoleId,
		RoleName:     res.RoleName,
		InventoryIds: res.InventoryIds,
		Status:       res.Status,
	}, nil
}

// GetEmpInfoShareToken 生成邀请员工加入 token
func (srv *empSrv) GetEmpInfoShareToken(ctx context.Context, brandId, storeId, empId int64) (string, lueerror.LueError) {
	uid := uuid.New().String()
	visit := &object.EmpVisitInfo{
		BrandId: brandId,
		StoreId: storeId,
		EmpId:   empId,
	}
	err := dao.GetEmployeeDao().CacheEmpVisitToken(ctx, uid, visit, 5*time.Hour)
	if err != nil {
		return "", lueerror.RedisErr(err)
	}
	return uid, nil
}

func (srv *empSrv) getShareTokenInfo(ctx context.Context, shareToken string) (*object.EmpVisitInfo, lueerror.LueError) {
	tokenInfo, err := dao.GetEmployeeDao().GetEmpVisitToken(ctx, shareToken)
	if err != nil {
		return nil, lueerror.RedisErr(err)
	}
	if tokenInfo == nil {
		return nil, lueerror.Forbidden(errors.New("分享已经过期"))
	}
	return tokenInfo, nil
}

// GetEmpInfoByShareToken 根据分享 token 获取员工信息
func (srv *empSrv) GetEmpInfoByShareToken(ctx context.Context, token string) (*pb.InvitationInfoReply, lueerror.LueError) {
	visitInfo, errL := srv.getShareTokenInfo(ctx, token)
	if errL != nil {
		return nil, errL
	}
	emp, errL := srv.getEmpInfoById(ctx, visitInfo.BrandId, visitInfo.EmpId, false)
	if errL != nil {
		return nil, errL
	}
	if emp == nil {
		return nil, lueerror.StoreNotExist(fmt.Errorf(fmt.Sprintf("员工 %d 不存在", visitInfo.EmpId)))
	}
	departName := ""
	var invitorId int64
	if visitInfo.StoreId > 0 {
		store, err := dao.GetStoreDao().GetStoreById(ctx, visitInfo.StoreId)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		if store == nil {
			return nil, lueerror.InvalidStore(fmt.Errorf("门店 %d 不存在", visitInfo.StoreId))
		}
		departName = store.Name
		invitorId = store.SupEmpId
	} else {
		brand, err := dao.GetBrandDao().GetBrandById(ctx, visitInfo.BrandId)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		if brand == nil {
			return nil, lueerror.InvalidBrand(fmt.Errorf("品牌 %d 不存在", visitInfo.BrandId))
		}
		departName = brand.Name
		invitorId = brand.SuEmpId
	}
	ret := &pb.InvitationInfoReply{
		EmpId:                emp.Id,
		Name:                 emp.Name,
		Mobile:               emp.Mobile,
		EntryDate:            util.TimeToDate(emp.EntryDate),
		RoleId:               0,
		RoleName:             "",
		DepartName:           departName,
		Invitor:              "",
		Status:               "",
		XXX_NoUnkeyedLiteral: struct{}{},
		XXX_unrecognized:     nil,
		XXX_sizecache:        0,
	}
	op, errL := srv.getOpInfoByEmpId(ctx, emp.Id, visitInfo.BrandId, visitInfo.StoreId, false)
	if errL != nil {
		return nil, errL
	}
	if op != nil {
		role, err := dao.GetRoleDao().GetEmpRoleById(ctx, op.RoleId)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		if role == nil {
			return nil, lueerror.InvalidRole(fmt.Errorf("角色 %d 不存在", role.Id))
		}
		invitorId = op.ModifyEmpId
		ret.RoleId = role.Id
		ret.RoleName = role.Name
	}
	if invitorId > 0 {
		invitor, errL := srv.getEmpInfoById(ctx, visitInfo.BrandId, invitorId, false)
		if errL != nil {
			return nil, errL
		}
		if invitor != nil {
			ret.Invitor = invitor.Name
		}
	}
	return ret, nil
}

// UpdateEmpInfo 更新员工信息
func (srv *empSrv) UpdateEmpInfo(ctx context.Context, brandId int64, p *pb.EmployeeUpdateReq, invitor int64) (*pb.EmployeeInfoReply, lueerror.LueError) {
	if p == nil {
		return nil, nil
	}
	ret, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		// 获取员工信息
		emp, errL := srv.getEmpInfoById(ctx, brandId, p.EmpId, true)
		if errL != nil {
			return nil, errL
		}
		if emp == nil {
			return nil, lueerror.InvalidEmployee(errors.New("员工不存在"))
		}
		if emp.Status == model.EmployeeStatusDepart {
			return nil, lueerror.InvalidEmployee(errors.New("员工已经离职"))
		}
		// 更新员工信息
		enDate, err := util.DateParse(p.EntryDate)
		if err != nil {
			return nil, lueerror.InvalidRequest(err)
		}
		emp.Update(p.Name, enDate)
		err = dao.GetEmployeeDao().UpdateEmployeeById(ctx, emp)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		// 角色检查
		role, errL := srv.getEmpRole(ctx, p.RoleId, brandId, p.StoreId)
		if errL != nil {
			return nil, errL
		}
		// 运营角色状态跟随员工状态
		opSt := model.OpStatusValid
		if emp.Status == model.EmployeeStatusInviting {
			opSt = model.OpStatusInviting
		}
		op, errL := srv.createOrUpdateOperator(ctx, brandId, p.StoreId, emp.Id, role.Id, invitor, opSt)
		if errL != nil {
			return nil, errL
		}
		// 仓库角色创建或更新
		errL = srv.createOrUpdateInventoryOperator(ctx, brandId, p.StoreId, emp.Id, p.InventoryIds, opSt, invitor)
		if errL != nil {
			return nil, errL
		}
		invOps, errL := srv.getInvOpInfoByEmpId(ctx, brandId, p.StoreId, emp.Id, false)
		if errL != nil {
			return nil, errL
		}
		return srv.employeeInfoAgg(emp, role, op, invOps), nil
	})
	if err != nil {
		return nil, parseLueerror(err)
	}
	res := ret.(*object.EmployeeInfo)
	return &pb.EmployeeInfoReply{
		EmpId:        res.EmpId,
		Name:         res.Name,
		Mobile:       res.Mobile,
		EntryDate:    util.TimeToDate(res.EntryDate),
		RoleId:       res.RoleId,
		RoleName:     res.RoleName,
		InventoryIds: res.InventoryIds,
		Status:       res.Status,
	}, nil
}

func (srv *empSrv) loadRolesMap(ctx context.Context, roleIds []int64) (map[int64]*model.EmpRole, lueerror.LueError) {
	if len(roleIds) == 0 {
		return nil, nil
	}
	roles, err := dao.GetRoleDao().GetEmpRolesByIds(ctx, roleIds)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	ret := make(map[int64]*model.EmpRole, len(roles))
	for _, r := range roles {
		ret[r.Id] = r
	}
	return ret, nil
}

// GetOperationList 加载运营列表
func (srv *empSrv) GetOperationList(ctx context.Context, brandId, storeId int64, status, search string, pg *object.Pagination) (*pb.EmployeeListReply, lueerror.LueError) {
	refId, refType := model.GetRefInfoForBrandStore(brandId, storeId)
	ops, total, err := dao.GetOperatorDao().GetOperators(ctx, brandId, refId, refType, model.GetInnerOpStatus(status), search, pg)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	// 提取角色信息
	roleIds := make([]int64, len(ops))
	for idx, e := range ops {
		roleIds[idx] = e.RoleId
	}
	rolesMap, errL := srv.loadRolesMap(ctx, roleIds)
	if errL != nil {
		return nil, errL
	}
	emps := make([]*pb.EmployeeSimpleInfo, len(ops))
	for idx, e := range ops {
		roleName := ""
		if r, ok := rolesMap[e.RoleId]; ok {
			roleName = r.Name
		}
		emps[idx] = &pb.EmployeeSimpleInfo{
			EmpId:    e.EmpId,
			Name:     e.Name,
			Mobile:   e.Mobile,
			Status:   e.GetStatus(),
			RoleId:   e.RoleId,
			RoleName: roleName,
		}
	}
	ret := &pb.EmployeeListReply{
		PageNo:    pg.PageNo,
		PageSize:  pg.PageSize,
		Total:     total,
		Employees: emps,
	}
	return ret, nil
}

// SendConfirmCode 发送确认短信
func (srv *empSrv) SendConfirmCode(ctx context.Context, shareToken, codeType string) lueerror.LueError {
	tokenInfo, errL := srv.getShareTokenInfo(ctx, shareToken)
	if errL != nil {
		return errL
	}
	emp, errL := srv.getEmpInfoById(ctx, tokenInfo.BrandId, tokenInfo.EmpId, false)
	if errL != nil {
		return errL
	}
	if emp == nil {
		return lueerror.InvalidEmployee(errors.New("员工不存在"))
	}
	err := dao.GetBilinVendorDao().SendAccConfirmCode(ctx, emp.Mobile, codeType)
	if err != nil {
		return lueerror.GrpcErr(err)
	}
	return nil
}

// 更新仓库运营状态
func (srv *empSrv) updateInvOpStatus(ctx context.Context, brandId, storeId, empId, modifier int64, op string) lueerror.LueError {
	// 更新仓库运营
	invOps, errL := srv.getInvOpInfoByEmpId(ctx, brandId, storeId, empId, true)
	if errL != nil {
		return errL
	}
	var updateOps []*model.Operator
	switch op {
	case "enable":
		for _, opt := range invOps {
			if opt.IsInviting() {
				if modifier == 0 {
					modifier = opt.ModifyEmpId
				}
				opt.Enable(modifier)
				updateOps = append(updateOps, opt)
			}
		}
	case "depart":
		for _, opt := range invOps {
			opt.Invalid(modifier)
			updateOps = append(updateOps, opt)
		}
	case "delete":
		for _, opt := range invOps {
			opt.Delete(modifier)
			updateOps = append(updateOps, opt)
		}
	}
	err := dao.GetOperatorDao().UpdateOperatorByIds(ctx, updateOps)
	if err != nil {
		return lueerror.DbErr(err)
	}
	return nil
}

// EmpConfirmInvitation 员工接收邀请
func (srv *empSrv) EmpConfirmInvitation(ctx context.Context, p *pb.EmployeeConfirmInvitationReq) lueerror.LueError {
	tokenInfo, errL := srv.getShareTokenInfo(ctx, p.ShareToken)
	if errL != nil {
		return errL
	}
	// 获取员工
	emp, errL := srv.getEmpInfoById(ctx, tokenInfo.BrandId, tokenInfo.EmpId, false)
	if errL != nil {
		return errL
	}
	if emp == nil {
		return lueerror.InvalidEmployee(errors.New("员工不存在"))
	}
	// 确认统一账号邀请
	gID, err := dao.GetBilinVendorDao().AccConfirmInvitation(ctx, emp.AccountId, p.OpenId, p.UnionId, p.Nickname, p.Avatar, p.Code, p.CodeType)
	if err != nil {
		return lueerror.GrpcErr(err)
	}
	_, err = dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		emp, errL = srv.getEmpInfoById(ctx, tokenInfo.BrandId, tokenInfo.EmpId, true)
		if errL != nil {
			return nil, errL
		}
		// 更新 employee 信息
		if emp.IsInviting() {
			emp.Enable(gID)
			err = dao.GetEmployeeDao().UpdateEmployeeById(ctx, emp)
			if err != nil {
				return nil, lueerror.DbErr(err)
			}
		}
		// 更新运营状态
		op, errL := srv.getOpInfoByEmpId(ctx, emp.Id, tokenInfo.BrandId, tokenInfo.StoreId, true)
		if errL != nil {
			return nil, errL
		}
		if op != nil && op.IsInviting() {
			op.Enable(op.ModifyEmpId)
			err = dao.GetOperatorDao().UpdateOperatorById(ctx, op)
			if err != nil {
				return nil, lueerror.DbErr(err)
			}
		}
		// 更新仓库运营
		errL = srv.updateInvOpStatus(ctx, tokenInfo.BrandId, tokenInfo.StoreId, emp.Id, 0, "enable")
		return nil, errL
	})
	return parseLueerror(err)
}

// OperatorDepart 运营员工离职
func (srv *empSrv) OperatorDepart(ctx context.Context, brandId int64, p *pb.EmployeeDepartReq, modifier int64) lueerror.LueError {
	if p == nil {
		return lueerror.InvalidRequest(errors.New("参数为空"))
	}
	_, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		op, errL := srv.getOpInfoByEmpId(ctx, p.EmpId, brandId, p.StoreId, true)
		if errL != nil {
			return nil, errL
		}
		if op == nil {
			return nil, lueerror.InvalidEmployee(fmt.Errorf("运营%d 身份不存在", p.EmpId))
		}
		// 置为离职状态
		op.Invalid(modifier)
		err := dao.GetOperatorDao().UpdateOperatorById(ctx, op)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		// 更新仓库运营离职
		errL = srv.updateInvOpStatus(ctx, brandId, p.StoreId, p.EmpId, modifier, "depart")
		return nil, errL
	})
	return parseLueerror(err)
}

// OperatorDelete 删除请求
func (srv *empSrv) OperatorDelete(ctx context.Context, brandId int64, p *pb.EmployeeDeleteReq, modifier int64) lueerror.LueError {
	if p == nil {
		return lueerror.InvalidRequest(errors.New("参数为空"))
	}

	_, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		op, errL := srv.getOpInfoByEmpId(ctx, p.EmpId, brandId, p.StoreId, true)
		if errL != nil {
			return nil, errL
		}
		if op == nil {
			return nil, lueerror.InvalidEmployee(fmt.Errorf("运营%d 身份不存在", p.EmpId))
		}
		// 置为删除状态
		op.Delete(modifier)
		err := dao.GetOperatorDao().DelOperatorById(ctx, op)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		// 删除仓库运营
		errL = srv.updateInvOpStatus(ctx, brandId, p.StoreId, p.EmpId, modifier, "delete")
		return nil, errL
	})
	return parseLueerror(err)
}

// OperatorReEnroll 运营重新加入
func (srv *empSrv) OperatorReEnroll(ctx context.Context, brandId int64, p *pb.EmployeeReEnrollReq, modifier int64) lueerror.LueError {
	if p == nil {
		return lueerror.InvalidRequest(errors.New("参数为空"))
	}

	_, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		op, errL := srv.getOpInfoByEmpId(ctx, p.EmpId, brandId, p.StoreId, true)
		if errL != nil {
			return nil, errL
		}
		if op == nil {
			return nil, lueerror.InvalidEmployee(fmt.Errorf("运营%d 身份不存在", p.EmpId))
		}
		op.Enable(modifier)
		err := dao.GetOperatorDao().UpdateOperatorById(ctx, op)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		// 仓库运营
		errL = srv.updateInvOpStatus(ctx, brandId, p.StoreId, p.EmpId, modifier, "enable")
		return nil, errL
	})
	return parseLueerror(err)
}

// 重置品牌超级管理员
func (srv *empSrv) resetBrandSupAdmin(ctx context.Context, brandId, supEmpId int64) lueerror.LueError {
	brand, err := dao.GetBrandDao().GetBrandById(ctx, brandId)
	if err != nil {
		return lueerror.DbErr(err)
	}
	if brand == nil {
		return lueerror.InvalidBrand(fmt.Errorf("品牌 %d 不存在", brandId))
	}
	if brand.SuEmpId != supEmpId {
		brand.AssignSuperAdmin(supEmpId)
		err = dao.GetBrandDao().UpdateBrandSuEmp(ctx, brand)
		if err != nil {
			return lueerror.DbErr(err)
		}
	}
	return nil
}

// 重置门店超级管理员
func (srv *empSrv) resetStoreSupAdmin(ctx context.Context, storeId, supEmpId int64) lueerror.LueError {
	store, err := dao.GetStoreDao().GetStoreById(ctx, storeId)
	if err != nil {
		return lueerror.DbErr(err)
	}
	if store == nil {
		return lueerror.InvalidBrand(fmt.Errorf("门店 %d 不存在", storeId))
	}
	if store.SupEmpId != supEmpId {
		store.AssignSumEmp(supEmpId)
		err = dao.GetStoreDao().UpdateStoreSupEmp(ctx, store)
		if err != nil {
			return lueerror.DbErr(err)
		}
	}
	// 发送更新消息
	dao.GetMessageDao().SendStoreUpdateMsg(ctx, store)
	return nil
}

// ResetSupAdmin 重置超管
func (srv *empSrv) ResetSupAdmin(ctx context.Context, brandId int64, p *pb.EmployeeSupAdminReq, modifier int64) lueerror.LueError {
	if p == nil {
		return lueerror.InvalidRequest(errors.New("参数为空"))
	}
	// 判断是修改品牌还是门店超管
	_, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		emp, errL := srv.getEmpInfoById(ctx, brandId, p.EmpId, true)
		if errL != nil {
			return nil, errL
		}
		if emp == nil {
			return nil, lueerror.InvalidEmployee(errors.New("员工不存在"))
		}
		if p.EmpId == modifier {
			return nil, nil
		}
		_, refType := model.GetRefInfoForBrandStore(brandId, p.StoreId)
		// 更新品牌超管
		if refType == model.RefTypeBrand {
			errL = srv.resetBrandSupAdmin(ctx, brandId, emp.Id)
			if errL != nil {
				return nil, errL
			}
		} else if refType == model.RefTypeStore {
			// 更新门店超管
			errL = srv.resetStoreSupAdmin(ctx, p.StoreId, emp.Id)
			if errL != nil {
				return nil, errL
			}
		} else {
			return nil, nil
		}
		// 将运营角色删除
		op, errL := srv.getOpInfoByEmpId(ctx, p.EmpId, brandId, p.StoreId, true)
		if errL != nil {
			return nil, errL
		}
		if op != nil {
			op.Delete(modifier)
			err := dao.GetOperatorDao().DelOperatorById(ctx, op)
			if err != nil {
				return nil, lueerror.DbErr(err)
			}
		}
		// 将仓库运营删除
		errL = srv.updateInvOpStatus(ctx, brandId, p.StoreId, p.EmpId, modifier, "delete")
		return nil, errL
	})
	return parseLueerror(err)
}

// GetSupAdmin 获取超级管理员
func (srv *empSrv) GetSupAdmin(ctx context.Context, brandId, storeId int64) (*pb.EmployeeInfoReply, lueerror.LueError) {
	var empId int64
	if storeId == 0 {
		brand, err := dao.GetBrandDao().GetBrandById(ctx, brandId)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		if brand == nil {
			return nil, lueerror.InvalidBrand(fmt.Errorf("无效的品牌 %d", brandId))
		}
		empId = brand.SuEmpId
	} else {
		store, err := dao.GetStoreDao().GetStoreById(ctx, storeId)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		if store == nil || store.BrandId != brandId {
			return nil, lueerror.InvalidStore(fmt.Errorf("无效的门店 %d", storeId))
		}
		empId = store.SupEmpId
	}

	emp, errL := srv.getEmpInfoById(ctx, brandId, empId, false)
	if errL != nil {
		return nil, errL
	}
	if emp == nil {
		return nil, lueerror.InvalidStore(fmt.Errorf("无效的员工 %d", empId))
	}
	return &pb.EmployeeInfoReply{
		EmpId:        emp.Id,
		Name:         emp.Name,
		Mobile:       emp.Mobile,
		EntryDate:    util.TimeToDate(emp.EntryDate),
		RoleId:       0,
		RoleName:     "超级管理员",
		InventoryIds: nil,
		Status:       emp.GetStatus(),
	}, nil
}

// GetEmpRelatedBrands 获取账号关联品牌
func (srv *empSrv) GetEmpRelatedBrands(ctx context.Context, accId string) (*pb.BrandsInfoV2Reply, lueerror.LueError) {
	// 根据统一账号id获取员工
	emps, err := dao.GetEmployeeDao().GetEmployeeRelatedTo(ctx, accId)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	brandIds := make([]int64, len(emps))
	for idx, emp := range emps {
		brandIds[idx] = emp.BrandId
	}
	brands, err := dao.GetBrandDao().GetBrandByIds(ctx, brandIds)
	rBrands := make([]*pb.BrandInfoV2Reply, len(brands))
	for idx, brand := range brands {
		rBrands[idx] = &pb.BrandInfoV2Reply{
			BrandId:   brand.Id,
			Name:      brand.Name,
			Logo:      brand.Logo,
			Desc:      brand.Description,
			CreatedAt: util.TimeToDate(brand.CreatedAt),
			IsCreator: brand.CreatorId == accId,
		}
	}
	return &pb.BrandsInfoV2Reply{Brands: rBrands}, nil
}

// GetEmpByBrandAndGID 通过brand_id和account_token获取员工简单信息
func (srv *empSrv) GetEmpByBrandAndGID(ctx context.Context, brandId int64, gId string) (*pb.EmployeeInfoBriefReply, lueerror.LueError) {
	emp, err := dao.GetEmployeeDao().GetEmpByBrandAndAccount(ctx, brandId, gId)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	if emp == nil {
		return nil, lueerror.InvalidEmployee(fmt.Errorf("员工不存在"))
	}
	ret := &pb.EmployeeInfoBriefReply{
		EmpId:   emp.Id,
		BrandId: emp.BrandId,
		Name:    emp.Name,
		Status:  emp.GetStatus(),
	}
	return ret, nil
}

// CredibleConfirmEmployee 服务端可信确认员工,此时映射的账号已经可用
func (srv *empSrv) CredibleConfirmEmployee(ctx context.Context, p *pb.CredibleConfirmEmployeeReq) lueerror.LueError {
	_, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		emp, errL := srv.getEmpInfoById(ctx, p.BrandId, p.EmpId, true)
		if errL != nil {
			return nil, errL
		}
		// 更新 employee 信息
		if emp.IsInviting() {
			emp.Enable(p.GId)
			err := dao.GetEmployeeDao().UpdateEmployeeById(ctx, emp)
			if err != nil {
				return nil, lueerror.DbErr(err)
			}
		}
		// 更新运营状态
		op, errL := srv.getOpInfoByEmpId(ctx, emp.Id, p.BrandId, p.StoreId, true)
		if errL != nil {
			return nil, errL
		}
		if op != nil && op.IsInviting() {
			op.Enable(op.ModifyEmpId)
			err := dao.GetOperatorDao().UpdateOperatorById(ctx, op)
			if err != nil {
				return nil, lueerror.DbErr(err)
			}
		}
		// 更新仓库运营
		errL = srv.updateInvOpStatus(ctx, p.BrandId, p.StoreId, emp.Id, 0, "enable")
		return nil, errL
	})
	return parseLueerror(err)
}
